package com.ruoyi.workflow.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.flowable.utils.ModelUtils;
import com.ruoyi.workflow.domain.WfDeployForm;
import com.ruoyi.workflow.domain.WfDeployFormDraft;
import com.ruoyi.workflow.domain.WfForm;
import com.ruoyi.workflow.domain.dto.WfDeployFormSaveInput;
import com.ruoyi.workflow.service.IWfDeployFormService;
import lombok.RequiredArgsConstructor;
import org.babyfish.jimmer.sql.JSqlClient;
import org.babyfish.jimmer.sql.ast.mutation.SaveMode;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.bpmn.model.UserTask;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 流程实例关联表单Service业务层处理
 *
 * @author KonBAI
 * @createTime 2022/3/7 22:07
 */

@RequiredArgsConstructor
@Service
public class WfDeployFormServiceImpl implements IWfDeployFormService {

    // private final WfDeployFormMapper baseMapper;
    //
    // private final WfFormMapper formMapper;
    private final JSqlClient sqlClient;

    /**
     * 新增流程实例关联表单
     *
     * @param deployForm 流程实例关联表单
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertWfDeployForm(WfDeployFormSaveInput deployForm) {
        // 删除部署流程和表单的关联关系
        sqlClient.deleteById(WfDeployForm.class, deployForm.getDeployId());
        // 新增部署流程和表单关系
        return sqlClient.saveCommand(deployForm.toEntity())
                .setMode(SaveMode.INSERT_ONLY)
                .execute()
                .getTotalAffectedRowCount();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveInternalDeployForm(String deployId, BpmnModel bpmnModel) {
        List<WfDeployForm> deployFormList = new ArrayList<>();
        // 获取开始节点
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        if (ObjectUtil.isNull(startEvent)) {
            throw new RuntimeException("开始节点不存在，请检查流程设计是否有误！");
        }
        // 保存开始节点表单信息
        WfDeployForm startDeployForm = buildDeployForm(deployId, startEvent);
        if (ObjectUtil.isNotNull(startDeployForm)) {
            deployFormList.add(startDeployForm);
        }
        // 保存用户节点表单信息
        Collection<UserTask> userTasks = ModelUtils.getAllUserTaskEvent(bpmnModel);
        if (CollUtil.isNotEmpty(userTasks)) {
            for (UserTask userTask : userTasks) {
                WfDeployForm userTaskDeployForm = buildDeployForm(deployId, userTask);
                if (ObjectUtil.isNotNull(userTaskDeployForm)) {
                    deployFormList.add(userTaskDeployForm);
                }
            }
        }
        // 批量新增部署流程和表单关联信息
        return sqlClient.saveEntitiesCommand(deployFormList)
                .setMode(SaveMode.INSERT_ONLY)
                .execute()
                .getTotalAffectedRowCount() > 0;
    }

/**
 * 查询流程挂着的表单
 *
 * @param deployId
 * @return
 */



    /**
     * 构建部署表单关联信息对象
     *
     * @param deployId 部署ID
     * @param node     节点信息
     * @return 部署表单关联对象。若无表单信息（formKey），则返回null
     */

    private WfDeployForm buildDeployForm(String deployId, FlowNode node) {
        String formKey = ModelUtils.getFormKey(node);
        if (StringUtils.isEmpty(formKey)) {
            return null;
        }
        String formId = StringUtils.substringAfter(formKey, "key_");
        WfForm wfForm = sqlClient.findById(WfForm.class, formId);
        if (ObjectUtil.isNull(wfForm)) {
            throw new ServiceException("表单信息查询错误");
        }
        return WfDeployFormDraft.$.produce(draft -> {
            draft.setDeployId(deployId);
            draft.setFormKey(formKey);
            draft.setNodeKey(node.getId());
            draft.setFormName(wfForm.formName());
            draft.setNodeName(node.getName());
            draft.setContent(wfForm.content());
        });
    }
}

